﻿#region summary

// Copyright (c)  YISH. All rights reserved.
// Licensed under the MIT License, See License.txt in the project root for license information.

#endregion

using System;
using NSQL.Expressions;
using NSQL.Expressions.Functions;
using NSQL.Sharpen;

namespace NSQL.Statements
{
    public class SelectElement : ISelectElement
    {
        public static readonly SelectElement Asterisk = new SelectElement(null);

        public IExpression Element { get; set; }

        public Identifier Alias { get; set; }

        public SelectElement(IExpression element, string alias)
        {
            Element = element;
            if (alias != null)
            {
                Alias = alias;
            }
        }
        public SelectElement(IExpression element, Identifier alias = null)
        {
            Element = element;
            Alias = alias;
        }

        public override string ToString() => $"{Element} {Alias}";
        object IDeepClone.DeepCopy()
        {
            return new SelectElement(Element.DeepClone(), Alias)
            {
                Tag = Tag
            };
        }

        public static explicit operator SelectElement(ConstantExpression valueExpression) =>
            new SelectElement(valueExpression);

        public static explicit operator SelectElement(ColumnExpression expression) => new SelectElement(expression);

        public static explicit operator SelectElement(CountFunction expression) => new SelectElement(expression);

        public static explicit operator SelectElement(SumFunction expression) => new SelectElement(expression);

        public static explicit operator SelectElement(MaxFunction expression) => new SelectElement(expression);

        public static explicit operator SelectElement(AvgFunction expression) => new SelectElement(expression);

        public static explicit operator SelectElement(MinFunction expression) => new SelectElement(expression);

        public static explicit operator SelectElement(AddIntervalFunction expression) => new SelectElement(expression);

        public static explicit operator SelectElement(ExtractFunction expression) => new SelectElement(expression);

        #region [ValueExpression]

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static explicit operator SelectElement(bool val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(byte val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(char val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(decimal val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(double val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(float val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(short val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(int val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(long val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(Guid val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// if wrapped with single quote will be ValueExpression, others will be ColumnExression.
        /// </summary>
        /// <param name="val"></param>
        public static implicit operator SelectElement(string val)
        {
            if (val.StartsWith("'") && val.EndsWith("'")) return (SelectElement) (ConstantExpression) val;
            return (SelectElement) new ColumnExpression(val);
        }

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(DateTime val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(TimeSpan val) => (SelectElement) (ConstantExpression) val;

        /// <summary>
        /// ValueExpression
        /// </summary>
        public static implicit operator SelectElement(byte[] val) => (SelectElement) (ConstantExpression) val;
        
        #endregion

        public object Tag { get; set; }
    }
}